#include <iostream>
using namespace std;

/*
	函数重载需要写N个版本的add，太啰嗦
	观察add有什么特征 --》返回值、形参类型有所不同
	   int add(int,int)
	   double add(double,double)
	   double add(double,int)
	大胆的想法--》把返回值类型，形参类型抽象出来--》用变量名字(比如：T)代替
	于是上面的add就变成了
	   T add(T a,T b)
	   {
		   
	   }
	模板：C++把函数的返回值类型，形参类型用变量替换，此时变量不叫作变量，专业术语叫做模板，模板就是把数据类型做了抽象
	模板分为两种：
	    第一种：模板函数
		第二种：模板类
*/
//定义一个模板函数
/*
	对比以前的函数：以前的函数都有具体类型
	模板函数：没有具体类型，没有写具体类型，用模板参数T来表示类型
*/
template<typename T>  //声明了一个模板，模板的名字叫T
T add(T a,T b)  //模板函数,由于你只是声明了一个模板参数，因此要求a和b，以及返回值类型必须相同
{
	cout<<"模板函数add被调用了"<<endl;
	return a+b;
}

int main()
{
	int n1=89;
	int n2=67;
	double n3=12.5;
	double n4=45.9;
	//调用模板函数--》跟普通函数的写法一样
	/*
		模板函数的底层原理：
		   26行到31行仅仅只是模板函数的一个定义，编译器无法得知T究竟是什么类型
		   调用函数的时候，编译器会依据程序员传递的实参类型去自动生成对应变量的add函数代码
		       比如：add(n1,n2);编译器会自动生成int add(int,int)这个版本的add函数定义
			         add(n3,n4);编译器会自动生成double add(double,double)这个版本的add函数定义
	*/
	add(n1,n2);
	add(n3,n4);
	//error: no matching function for call to ‘add(int&, double&)’
	//add(n1,n3); //原因n1和n3类型不一致，但是模板函数要求一致(模板函数仅仅用了一个模板参数)
}